/*******************************************************************
* Copyright (c) 2010 BSUIR <romkisel@gmail.com>

* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:

* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
********************************************************************/

#include <QtGui>
#include <QMessageBox>
#include "ui_dlightDialog.h"
#include "shadowmap.h"
#include "optixscene.h"
#include "border.h"
#include "plight.h"
#include "dlight.h"
#include "mirror.h"
#include "pixmapitem.h"
#include "optixitem.h"
#include "geometry.h"

#define ABOUT \
     tr("<h1>Optix</h1>"\
        "<i>Simple phisics sandbox on optics</i>"\
        "<p>copyright (c) 2010 BSUIR "\
        " (<a href='mailto:romkisel@gmail.com'>romkisel@gmail.com</a>)")

OptixScene::OptixScene(QObject * prnt)
    : QGraphicsScene(prnt), shadMap(cSceneW, cSceneH)
{
    this->setSceneRect(-cSceneW/2.0, -cSceneH/2.0, cSceneW, cSceneH);
    //this->setBackgroundBrush(QBrush(QPixmap(":/images/oak_full.jpg")));

    //this->addItem(&shadMap);
    this->densityAir = 1;

    this->curMode = ordinary;
    this->curSaveMode = unnamed;

    //this item need to get drop event
    //FIXME: drop event can't accept by QGraphicsScene
    dropRect = new QGraphicsRectItem(-cSceneW/2.0, -cSceneH/2.0, cSceneW, cSceneH);
    dropRect->setFlag(QGraphicsItem::ItemIsMovable, false);
    dropRect->setFlag(QGraphicsItem::ItemIsSelectable, false);
    dropRect->setAcceptDrops(true);
    this->addItem(dropRect);
}
//===========================================================================
// Slots signal, when scene is changing selected items
//===========================================================================
void OptixScene::selectItem()
{
    if (selectedItems().size() == 1)
    {
        QList<QAction *> acts = contextMenu->actions();
        QList<QAction *> tacts = toolBar->actions();
        acts[0]->setEnabled(true);
        acts[1]->setEnabled(true);

        tacts[4]->setEnabled(true);
        tacts[5]->setEnabled(true);

        QGraphicsItem *item = selectedItems().first();
        TransparentBorder *tb;
        PLight *pl;
        DLight *dl;
        if ((tb = dynamic_cast<TransparentBorder *>(item)) ||
            (pl = dynamic_cast<PLight *>(item)) ||
            (dl = dynamic_cast<DLight *>(item)))
        {
            acts[7]->setEnabled(true);
            tacts[7]->setEnabled(true);
        }
    }
    else
    {
        QList<QAction *> acts = contextMenu->actions();
        QList<QAction *> tacts = toolBar->actions();
        //set unactive some actions
        acts[0]->setEnabled(false);
        acts[1]->setEnabled(false);
        acts[3]->setEnabled(false);

        tacts[4]->setEnabled(false);
        tacts[5]->setEnabled(false);
        tacts[7]->setEnabled(false);
    }
}
//===========================================================================
// Rotate item on angle value
//===========================================================================
void OptixScene::rotateItem(QGraphicsItem *item, int value)
{
    qreal scX;
    qreal scY;
    QTransform newTrans;

    //FIXME: item->rotation() doesn't work!
    OptixItem *oi;
    if (oi = dynamic_cast<OptixItem *>(item))
    {
        scX = oi->getScX();
        scY = oi->getScY();
        oi->setAngle(value);
    }

    newTrans.rotate(value);
    newTrans.scale(scX, scY);
    item->setTransform(newTrans);
}
//===========================================================================
// Scale item on sx, sy
//===========================================================================
void OptixScene::scaleItem(QGraphicsItem *item, qreal sx, qreal sy)
{
    QTransform newTrans;
    qreal angle;
    qreal scX;
    qreal scY;

    PixmapItem *pi;
    PLight *pl;
    if (pi = dynamic_cast<PixmapItem *>(item))
    {
        return;
    }
    if (pl = dynamic_cast<PLight *>(item))
    {
        return;
    }
    OptixItem *oi;
    if (oi = dynamic_cast<OptixItem *>(item))
    {
        if (sx != -1)
            oi->setScX(sx/50);
        if (sy != -1)
            oi->setScY(sy/50);
        angle = oi->getAngle();
        scX = oi->getScX();
        scY = oi->getScY();
    }

    newTrans.rotate(angle);
    newTrans.scale(scX, scY);
    item->setTransform(newTrans);
}
//===========================================================================
// Rotate items when slider changes it's value
//===========================================================================
void OptixScene::srlRotateChange(int value)
{
    QList<QGraphicsItem *> itemList = selectedItems();

    for (int i = 0; i < itemList.size(); ++i)
    {
        rotateItem(itemList[i], value);
    }
}
//===========================================================================
// Scale items when slider changes it's value
//===========================================================================
void OptixScene::srlScaleChange(int value)
{
    QList<QGraphicsItem *> itemList = selectedItems();
    for (int i = 0; i < itemList.size(); ++i)
    {
        scaleItem(itemList[i], value, value);
    }
}
//===========================================================================
// Scale items when slider changes it's value
//===========================================================================
void OptixScene::srlScaleXChange(int value)
{
    QList<QGraphicsItem *> itemList = selectedItems();

    for (int i = 0; i < itemList.size(); ++i)
    {
        scaleItem(itemList[i], value, -1);
    }
}
//===========================================================================
// Scale items when slider changes it's value
//===========================================================================
void OptixScene::srlScaleYChange(int value)
{
    QList<QGraphicsItem *> itemList = selectedItems();

    for (int i = 0; i < itemList.size(); ++i)
    {
        scaleItem(itemList[i], -1, value);
    }
}
//===========================================================================
// Draws direct & point lights
//===========================================================================
void OptixScene::drawLigths()
{
    QList<PLight *> mPLights = getPLights();
    QList<DLight *> mDLights = getDLights();
    shadMap.clearShadowMap();

    for (int i = 0; i < mPLights.size(); ++i)
    {
        mPLights[i]->drawLight();
    }

    for (int i = 0; i < mDLights.size(); ++i)
    {
        drawDLights(mDLights[i]);
    }
}
//===========================================================================
// calculate & draw shadows from point light
//===========================================================================
void OptixScene::drawPShadows()
{
    QList<PLight *> mPLights = getPLights();
    if (mPLights.size() == 0) return;       //no lights
    //brush for shadows
    QColor shadowCol = shadMap.getColor();
    QBrush brush(QColor(shadowCol.red(),shadowCol.green(),shadowCol.blue(),
                        shadowCol.alpha()/mPLights.size()));

    QList<Border *> mBorders = getBorders();
    for (int k = 0; k < mPLights.size(); ++k)               //for all point light
    {
        PLight *ligth = mPLights[k];
        QPointF ligPoint = ligth->pos();                    //light position
        for (int i = 0; i < mBorders.size(); ++i)           //for all borders
        {
            //get the position & orientation of border
            QTransform transform = mBorders[i]->sceneTransform();
            QPolygonF curPoly = transform.map(mBorders[i]->polygon());

            QPointF shPo, shPo2;
            int polySize = curPoly.size();
            for (int j = 0; j < polySize; ++j)              //for all points of borders
            {
                QPointF curPoint = curPoly[j];
                QPointF nextPoint = curPoly[(j+1)%polySize];

                QVector2D curToNext(nextPoint.x()-curPoint.x(), nextPoint.y()-curPoint.y());
                QVector2D normal(curToNext.y(), -1*curToNext.x());
                QVector2D lightToCur(curPoint.x()-ligPoint.x(), curPoint.y()-ligPoint.y());
                //if side of border look in other side of ligth
                if ((normal.x()*lightToCur.x() + normal.y()*lightToCur.y()) < 0)    //dot product
                {
                    //add point in shadow's polygon
                    qreal dif = 10*mBorders[i]->getH()/ligth->getH();
                    //project points
                    shPo.setX(ligPoint.x() + dif*(curPoint.x()-ligPoint.x()));
                    shPo.setY(ligPoint.y() + dif*(curPoint.y()-ligPoint.y()));
                    shPo2.setX(ligPoint.x() + dif*(nextPoint.x()-ligPoint.x()));
                    shPo2.setY(ligPoint.y() + dif*(nextPoint.y()-ligPoint.y()));

                    QPolygonF shadowPolygon;
                    shadowPolygon << curPoint << nextPoint << shPo2 << shPo;

                    QPolygonF shPoly;
                    for (int l = 0; l < shadowPolygon.size(); ++l)
                    {
                        shPoly << shadowPolygon[l] + QPoint(shadMap.getMap()->width()/2,
                                                            shadMap.getMap()->height()/2);
                    }

                    //draw the shadow
                    QPainter p(shadMap.getMap());
                    p.setPen(Qt::NoPen);
                    p.setBrush(brush);
                    p.drawPolygon(shPoly);
                }
            }
        }
    }
}
//===========================================================================
// lunchs ray tracing
//===========================================================================
void OptixScene::drawDLights(DLight *light)
{
    QPolygonF poly;
    poly << QPointF(0, -light->getD()/2)
         << QPointF(light->getLength(), -light->getD()/2)
         << QPointF(light->getLength(), light->getD()/2)
         << QPointF(0, light->getD()/2);

    QLineF line;
    QTransform transform = light->sceneTransform();

    //FIXME: any ray can't begin inside TransbarentBorder
    poly = transform.map(poly);
    int N = light->getNumLines();
    qreal dt = light->getD()/(qreal)N;

    for (int i = 1; i < N; ++i)
    {
        line.setP1(QPointF(0, -light->getD()/2+dt*i));
        line.setP2(QPointF(light->getLength(), -light->getD()/2+dt*i));
        line = transform.map(line);

        traceStack.clear();
        traceRay(light, line);
    }
}
//===========================================================================
// tracing of the ray
//===========================================================================
void OptixScene::traceRay(DLight *light, QLineF line)
{
    int dist = 30000;
    int numNear = -1;
    int numjNear = -1;
    QPointF nearIntersectPoint;
    enum objType {mirror, border, tborder} typeNear = mirror;

    QPointF intersectPoint;
    QList<Border *> mBorders = getBorders();
    QList<Mirror *> mMirrors = getMirrors();
    QList<TransparentBorder *> mTBorders = getTBorders();

    for (int i = 0; i < mBorders.size(); ++i)
    {
        QTransform pTrans = mBorders[i]->sceneTransform();
        QPolygonF p = pTrans.map(mBorders[i]->polygon());
        for (int j = 0; j < p.size(); ++j)
        {
            QLineF curLine(p[j], p[(j+1)%p.size()]);
            if (line.intersect(curLine, &intersectPoint) == QLineF::BoundedIntersection)
            {
                if (pointDistance(line.p1(), intersectPoint) < dist)
                {
                    dist = pointDistance(line.p1(), intersectPoint);
                    typeNear = border;
                    numNear = i;
                    numjNear = j;
                    nearIntersectPoint = intersectPoint;
                }
            }
        }
    }
    for (int i = 0; i < mMirrors.size(); ++i)
    {
        QTransform pTrans = mMirrors[i]->sceneTransform();
        QPolygonF p = pTrans.map(mMirrors[i]->polygon());
        for (int j = 0; j < p.size(); ++j)
        {
            QLineF curLine(p[j], p[(j+1)%p.size()]);
            if (line.intersect(curLine, &intersectPoint) == QLineF::BoundedIntersection)
            {
                if ((pointDistance(line.p1(), intersectPoint) > EPS) &&
                    (pointDistance(line.p1(), intersectPoint) < dist))
                {
                    dist = pointDistance(line.p1(), intersectPoint);
                    typeNear = mirror;
                    numNear = i;
                    numjNear = j;
                    nearIntersectPoint = intersectPoint;
                }
            }
        }
    }
    for (int i = 0; i < mTBorders.size(); ++i)
    {
        QTransform pTrans = mTBorders[i]->sceneTransform();
        QPolygonF p = pTrans.map(mTBorders[i]->polygon());
        for (int j = 0; j < p.size(); ++j)
        {
            QLineF curLine(p[j], p[(j+1)%p.size()]);
            if (line.intersect(curLine, &intersectPoint) == QLineF::BoundedIntersection)
            {
                if ((pointDistance(line.p1(), intersectPoint) > EPS) &&
                    (pointDistance(line.p1(), intersectPoint) < dist))
                {
                    dist = pointDistance(line.p1(), intersectPoint);
                    typeNear = tborder;
                    numNear = i;
                    numjNear = j;
                    nearIntersectPoint = intersectPoint;
                }
            }
        }
    }

    if (numNear != -1)
    {
        if (typeNear == border)
        {
            light->drawLightLine(QLineF(line.p1(), nearIntersectPoint));
        }
        if (typeNear == mirror)
        {
            QTransform transf = mMirrors[numNear]->sceneTransform();
            QPolygonF p = transf.map(mMirrors[numNear]->polygon());
            QLineF l(p[numjNear], p[(numjNear+1)%p.size()]);

            //draw line before reflect
            light->drawLightLine(QLineF(line.p1(), nearIntersectPoint));
            qreal leng;
            QPointF reflectedPoint = translatePoint(line.p2(),
                                     projectPoint(l.p1(), l.p2(), line.p2(), leng));
            traceRay(light, QLineF(nearIntersectPoint, reflectedPoint));
        }
        if (typeNear == tborder)
        {
            QTransform transf = mTBorders[numNear]->sceneTransform();
            QPolygonF p = transf.map(mTBorders[numNear]->polygon());
            QLineF l(p[numjNear], p[(numjNear+1)%p.size()]);

            qreal crProd = crossProd(line, l)/(line.length()*l.length());
            //qreal dtProd = dotProd(line, l)/(line.length()*l.length());

            qreal sin1 = fabs(crProd);
            qreal densityFrom;
            qreal densityTo;
            if (traceStack.isEmpty())
            {
                densityFrom = densityAir;
                densityTo = mTBorders[numNear]->getN();
                traceStack.push(mTBorders[numNear]);
            }
            else
            {
                TransparentBorder *from = traceStack.top();
                if (from != mTBorders[numNear])
                {
                    densityFrom = from->getN();
                    densityTo = mTBorders[numNear]->getN();
                    traceStack.push(mTBorders[numNear]);
                }
                else
                {
                    densityFrom = from->getN();
                    traceStack.pop();
                    if (traceStack.isEmpty())
                    {
                        densityTo = densityAir;
                    }
                    else
                    {
                        densityTo = traceStack.top()->getN();
                    }
                }
            }
            qreal sin2 = (densityFrom/densityTo)*sin1;
            QPointF newP2;
            if (sin2 <= 1)
            {
                qreal angDelta = fabs(asin(sin1) - asin(sin2));
                if (crProd > 0)
                    newP2 = turnPoint(nearIntersectPoint, line.p2(), -angDelta);
                else
                    newP2 = turnPoint(nearIntersectPoint, line.p2(), angDelta);
            }
            if (sin2 > 1)
            {
                qreal leng;
                newP2 = translatePoint(line.p2(),
                                         projectPoint(l.p1(), l.p2(), line.p2(), leng));
                traceStack.push(mTBorders[numNear]);
            }
            light->drawLightLine(QLineF(line.p1(), nearIntersectPoint));
            traceRay(light, QLineF(nearIntersectPoint, newP2));
        }
    }
    else
    {
        light->drawLightLine(line);
    }
}
//===========================================================================
// this function draw a foreground of scene
//===========================================================================
void OptixScene::drawForeground(QPainter * painter, const QRectF & rect)
{
    if (curMode == rotate)
    {
        if (curSelectItem)
        {
            QPixmap pixm(":images/arrow_cycle.png");
            painter->setOpacity(0.6);
            painter->drawPixmap(curSelectItem->pos().x() - pixm.width()/2,
                                curSelectItem->pos().y() - pixm.height()/2,
                                pixm);
            painter->setOpacity(1);
        }
    }
    if (curMode == scale)
    {
        if (curSelectItem)
        {
            QPixmap pixm(":images/arrow_diagleft.png");
            painter->setOpacity(0.6);
            painter->drawPixmap(curSelectItem->pos().x() - pixm.width()/2,
                                curSelectItem->pos().y() - pixm.height()/2,
                                pixm);
            painter->setOpacity(1);
        }
    }
}
//===========================================================================
// draw shadowmap
//===========================================================================
void OptixScene::drawBackground(QPainter * painter, const QRectF & rect)
{
    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setBrush(QBrush(QPixmap(":/images/oak_full.jpg")));
    painter->drawRect(-cSceneW/2, -cSceneH/2, cSceneW, cSceneH);

    painter->drawImage(-cSceneW/2, -cSceneH/2, *this->shadMap.getMap());
}
//===========================================================================
// always calls when scene is changing
//===========================================================================
void OptixScene::changeDraw(const QList<QRectF> &)
{
    drawLigths();
    drawPShadows();
}
//===========================================================================
// delete all selected items
//===========================================================================
void OptixScene::deleteItems()
{
    foreach (QGraphicsItem *item, this->selectedItems())
    {
        this->removeItem(item);
    }
}
//===========================================================================
//===========================================================================
void OptixScene::actionRotate()
{
    if (selectedItems().size() == 1)
    {
        foreach (QGraphicsView *view, this->views())
            view->setDragMode(QGraphicsView::NoDrag);
        curSelectItem = selectedItems()[0];
        for (int i = 0; i < this->items().size(); ++i)
            items()[i]->setFlag(QGraphicsItem::ItemIsMovable, false);
        clearSelection();
        curMode = rotate;
    }
}
//===========================================================================
//===========================================================================
void OptixScene::actionScale()
{
    if (selectedItems().size() == 1)
    {
        foreach (QGraphicsView *view, this->views())
            view->setDragMode(QGraphicsView::NoDrag);
        curSelectItem = selectedItems()[0];
        for (int i = 0; i < this->items().size(); ++i)
            items()[i]->setFlag(QGraphicsItem::ItemIsMovable, false);
        clearSelection();
        curMode = scale;
    }
}
//===========================================================================
//===========================================================================
void OptixScene::setContextMenu(QMenu *menu)
{
    contextMenu = menu;
}
//===========================================================================
//===========================================================================
void OptixScene::setToolBar(QToolBar *toolBar)
{
    this->toolBar = toolBar;
}
//===========================================================================
//===========================================================================
void OptixScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (curMode == rotate)
    {
        //FIXME: mouseEvent->button() & Qt::LeftButton doesn't work!
        if (curSelectItem)
        {
            qreal angle = lineAngle(curSelectItem->pos(), mouseEvent->scenePos());
            rotateItem(curSelectItem, angle);
        }
    }
    if (curMode == scale)
    {
        if (curSelectItem)
        {
            qreal scX = fabs(curSelectItem->pos().x() - mouseEvent->scenePos().x());
            qreal scY = fabs(curSelectItem->pos().y() - mouseEvent->scenePos().y());
            scaleItem(curSelectItem, scX, scY);
        }
    }
    QGraphicsScene::mouseMoveEvent(mouseEvent);
}
//===========================================================================
//===========================================================================
void OptixScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (curMode == rotate)
    {
        if (mouseEvent->button() & Qt::RightButton)
        {
            curMode = ordinary;
            foreach (QGraphicsView *view, this->views())
                view->setDragMode(QGraphicsView::RubberBandDrag);
            for (int i = 0; i < this->items().size(); ++i)
                items()[i]->setFlag(QGraphicsItem::ItemIsMovable, true);
            dropRect->setFlag(QGraphicsItem::ItemIsMovable, false);
            update(sceneRect());
        }
    }
    if (curMode == scale)
    {
        if (mouseEvent->button() & Qt::RightButton)
        {
            curMode = ordinary;
            foreach (QGraphicsView *view, this->views())
                view->setDragMode(QGraphicsView::RubberBandDrag);
            for (int i = 0; i < this->items().size(); ++i)
                items()[i]->setFlag(QGraphicsItem::ItemIsMovable, true);
            dropRect->setFlag(QGraphicsItem::ItemIsMovable, false);
            update(sceneRect());
        }
    }
    QGraphicsScene::mousePressEvent(mouseEvent);
}
//===========================================================================
//===========================================================================
void OptixScene::actionToFront()
{
    if (this->selectedItems().isEmpty())
        return;

    QGraphicsItem *selectedItem = this->selectedItems().first();
    QList<QGraphicsItem *> overlapItems = selectedItem->collidingItems();

    qreal zValue = 0;
    foreach (QGraphicsItem *item, overlapItems)
    {
        if (item != &shadMap)
        {
            zValue = item->zValue() + 0.1;
        }
    }
    selectedItem->setZValue(zValue);
}
//===========================================================================
//===========================================================================
void OptixScene::actionToBack()
{
    if (this->selectedItems().isEmpty())
        return;

    QGraphicsItem *selectedItem = this->selectedItems().first();
    QList<QGraphicsItem *> overlapItems = selectedItem->collidingItems();

    qreal zValue = 0;
    foreach (QGraphicsItem *item, overlapItems)
    {
        if (item != &shadMap)
        {
            zValue = item->zValue() - 0.1;
        }
    }
    selectedItem->setZValue(zValue);
}
//===========================================================================
//===========================================================================
void OptixScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    if (event->mimeData()->hasFormat("text/plain"))
    {
        event->acceptProposedAction();
    }
}
//===========================================================================
//===========================================================================
void OptixScene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    QString str = event->mimeData()->text();
    QPointF pos = event->scenePos();

    if (str == QString("borderIcon"))
    {
        addBorder(pos);
    }
    else if (str == QString("triangleIcon"))
    {
        addBorderTriangle(pos);
    }
    else if (str == QString("gexagonIcon"))
    {
        addBorderGexagon(pos);
    }
    else if (str == QString("tbordIcon"))
    {
        addTPlate(pos);
    }
    else if (str == QString("prismIcon"))
    {
        addTrianglePrism(pos);
    }
    else if (str == QString("mirrorIcon"))
    {
        addMirror(pos);
    }
    else if (str == QString("convLens"))
    {
        addConvexLens(pos);
    }
    else if (str == QString("convLens2"))
    {
        addConvexLens2(pos);
    }
    else if (str == QString("concLens"))
    {
        addConcaveLens(pos);
    }
    else if (str == QString("concLens2"))
    {
        addConcaveLens2(pos);
    }
    else if (str == QString("plightIcon"))
    {
        addPLight(pos);
    }
    else if (str == QString("dlightIcon"))
    {
        addDLight(pos);
    }
    else if (str == QString("ruler"))
    {
        addRuler(pos);
    }
    else if (str == QString("trans"))
    {
        addProtractor(pos);
    }
}
//===========================================================================
//===========================================================================
void OptixScene::addPLight(QPointF pos)
{
    PLight *pl = new PLight(&shadMap);
    this->addItem(pl);
    pl->setPos(pos);
}

void OptixScene::addDLight(QPointF pos)
{
    DLight *dl = new DLight(&shadMap);
    this->addItem(dl);
    dl->setPos(pos);
}

void OptixScene::addBorder(QPointF pos)
{
    Border *b = new Border();
    this->addItem(b);
    b->setPos(pos);
}

void OptixScene::addBorderGexagon(QPointF pos)
{
    QPolygonF poly;
    poly << QPointF(20, -10) << QPointF(0, -20) << QPointF(-20, -10)
         << QPointF(-20, 10) << QPointF(0, 20) << QPointF(20, 10);

    Border *b = new Border(5, &poly);
    this->addItem(b);
    b->setPos(pos);
}

void OptixScene::addBorderTriangle(QPointF pos)
{
    QPolygonF poly;
    poly << QPointF(0, -20) << QPointF(-20, 20) << QPointF(20, 20);

    Border *b = new Border(5, &poly);
    this->addItem(b);
    b->setPos(pos);
}

void OptixScene::addMirror(QPointF pos)
{
    Mirror *m = new Mirror();
    this->addItem(m);
    m->setPos(pos);
}

void OptixScene::addTPlate(QPointF pos)
{
    QPolygonF poly;
    poly << QPointF(100, 20) << QPointF(100, -20) <<
            QPointF(-100, -20) << QPointF(-100, 20);
    TransparentBorder *tb = new TransparentBorder(&poly);
    this->addItem(tb);
    tb->setPos(pos);
}

void OptixScene::addTrianglePrism(QPointF pos)
{
    QPolygonF poly;
    poly << QPointF(100, 100) << QPointF(100, -100) << QPointF(-100, 100);
    TransparentBorder *tb = new TransparentBorder(&poly);
    this->addItem(tb);
    tb->setPos(pos);
}

void OptixScene::addConvexLens(QPointF pos)
{
    QPolygonF poly;
    int N = 30;
    qreal R = 200;
    qreal x = 40;
    qreal maxAlpha = fabs(acos(1 - x/R));
    qreal dAlpha = maxAlpha/N;
    qreal alpha;
    for (alpha = maxAlpha; alpha > -maxAlpha; alpha-=dAlpha)
    {
        poly << QPointF(R*cos(alpha)-R+x, R*sin(alpha));
    }
    int k = poly.size();
    for (int i = k-1; i >= 0; --i)
    {
        QPointF p = poly[i];
        poly << QPointF(-p.x(), p.y());
    }

    TransparentBorder *tb1 = new TransparentBorder(&poly, 1.33);
    this->addItem(tb1);
    tb1->setPos(pos);
}

void OptixScene::addConvexLens2(QPointF pos)
{
    QPolygonF poly;
    int N = 30;
    qreal R = 200;
    qreal x = 40;
    qreal maxAlpha = fabs(acos(1 - x/R));
    qreal dAlpha = maxAlpha/N;
    qreal alpha;
    for (alpha = maxAlpha; alpha > -maxAlpha; alpha-=dAlpha)
    {
        poly << QPointF(R*cos(alpha)-R+x, R*sin(alpha));
    }

    TransparentBorder *tb1 = new TransparentBorder(&poly, 1.33);
    this->addItem(tb1);
    tb1->setPos(pos);
}

void OptixScene::addConcaveLens(QPointF pos)
{
    QPolygonF poly;
    int N = 30;
    qreal R = 200;
    qreal x = 40;
    qreal maxAlpha = fabs(acos(1 - x/R));
    qreal dAlpha = maxAlpha/N;
    qreal alpha;
    for (alpha = PI - maxAlpha; alpha < PI + maxAlpha; alpha+=dAlpha)
    {
        poly << QPointF(R*cos(alpha)+R+x/2, R*sin(alpha));
    }
    int k = poly.size();
    for (int i = k-1; i >= 0; --i)
    {
        QPointF p = poly[i];
        poly << QPointF(-p.x(), p.y());
    }

    TransparentBorder *tb1 = new TransparentBorder(&poly, 1.33);
    this->addItem(tb1);
    tb1->setPos(pos);
}

void OptixScene::addConcaveLens2(QPointF pos)
{
    QPolygonF poly;
    int N = 30;
    qreal R = 200;
    qreal x = 40;
    qreal maxAlpha = fabs(acos(1 - x/R));
    qreal dAlpha = maxAlpha/N;
    qreal alpha;
    for (alpha = PI - maxAlpha; alpha < PI + maxAlpha; alpha+=dAlpha)
    {
        poly << QPointF(R*cos(alpha)+R+x/2, R*sin(alpha));
    }
    poly << QPointF(0, R*sin(PI + maxAlpha)) << QPointF(0, R*sin(PI - maxAlpha));

    TransparentBorder *tb1 = new TransparentBorder(&poly, 1.33);
    this->addItem(tb1);
    tb1->setPos(pos);
}

void OptixScene::addRuler(QPointF pos)
{
    QImage ruler(":images/ruler30.png");
    PixmapItem *px = new PixmapItem(ruler);
    this->addItem(px);
    px->setPos(pos);
    px->setFlag(QGraphicsItem::ItemIsMovable, true);
    px->setFlag(QGraphicsItem::ItemIsSelectable, true);
}

void OptixScene::addProtractor(QPointF pos)
{
    QImage prot(":images/protractor.png");

    prot.setAlphaChannel(prot.createMaskFromColor(QColor(255, 0, 128).rgb(), Qt::MaskOutColor));
    PixmapItem *px = new PixmapItem(prot);
    this->addItem(px);
    px->setPos(pos);
    px->setFlag(QGraphicsItem::ItemIsMovable, true);
    px->setFlag(QGraphicsItem::ItemIsSelectable, true);
}
/////////////////////////////////////////////////////////////////////////////
void OptixScene::actionColor()
{
    //QColor color = QColorDialog::getColor(Qt::green, this);
    QColor color = QColorDialog::getColor();
    OptixItem *oi;
    Border *b;
    Mirror *m;
    TransparentBorder *tb;
    PLight *pl;
    DLight *dl;
    foreach(QGraphicsItem *item, selectedItems())
    {
        if (oi = dynamic_cast<OptixItem *>(item))
        {
            oi->setColor(color);
        }
        if (b = dynamic_cast<Border *>(item))
        {
            b->changeColor();
        }
        else if (m = dynamic_cast<Mirror *>(item))
        {
            m->changeColor();
        }
        else if (tb = dynamic_cast<TransparentBorder *>(item))
        {
            tb->changeColor();
        }
        else if (pl = dynamic_cast<PLight *>(item))
        {
            pl->changeColor();
        }
    }
    this->update();
}
/////////////////////////////////////////////////////////////////////////////
void OptixScene::actionSettings()
{
    if (selectedItems().size() > 0)
    {
        QGraphicsItem *item = selectedItems().first();
        TransparentBorder *tb;
        PLight *pl;
        DLight *dl;

        if (tb = dynamic_cast<TransparentBorder *>(item))
        {
            bool ok;
            double d = QInputDialog::getDouble(this->views().first(), tr("Transparen border"),
                                               tr("n:"),
                                               tb->getN(),
                                               -100, 100, 2, &ok);
            if (ok)
                tb->setN(d);
        }
        else if (pl = dynamic_cast<PLight *>(item))
        {
            bool ok;
            int d = QInputDialog::getInt(this->views().first(), tr("Point light"),
                                               tr("Size:"),
                                               pl->getSize(),
                                               10, this->cSceneW, 20, &ok);
            if (ok)
                pl->setSize(d);
        }
        else if (dl = dynamic_cast<DLight *>(item))
        {
            QDialog dialog;
            Ui_dlightDialog dlg;
            dlg.setupUi(&dialog);
            dlg.spinD->setValue(dl->getD());
            dlg.spinN->setValue(dl->getNumLines());
            dlg.spinRayD->setValue(dl->getLineSize());
            dlg.spinSize->setValue(dl->getLength());

            if (dialog.exec())
            {
                dl->setD(dlg.spinD->value());
                dl->setNumLines(dlg.spinN->value());
                dl->setLength(dlg.spinSize->value());
                dl->setLineSize(dlg.spinRayD->value());
            }
        }
        this->update();
    }
}
/////////////////////////////////////////////////////////////////////////////
void OptixScene::actionAbout()
{
    QMessageBox msgBox;
    msgBox.information(this->views().first(), tr("About"), ABOUT);
}
/////////////////////////////////////////////////////////////////////////////
QMenu * OptixScene::ContextMenu()
{
    return this->contextMenu;
}

QList<Border *> OptixScene::getBorders()
{
    QList<Border *> resList;
    Border *item;
    QList<QGraphicsItem *> items = this->items();
    for (int i = 0; i < items.size(); ++i)
    {
        if (item = dynamic_cast<Border *>(items[i]))
        {
            resList << item;
        }
    }
    return resList;
}

QList<TransparentBorder *> OptixScene::getTBorders()
{
    QList<TransparentBorder *> resList;
    TransparentBorder *item;
    QList<QGraphicsItem *> items = this->items();
    for (int i = 0; i < items.size(); ++i)
    {
        if (item = dynamic_cast<TransparentBorder *>(items[i]))
        {
            resList << item;
        }
    }
    return resList;
}

QList<Mirror *> OptixScene::getMirrors()
{
    QList<Mirror *> resList;
    Mirror *item;
    QList<QGraphicsItem *> items = this->items();
    for (int i = 0; i < items.size(); ++i)
    {
        if (item = dynamic_cast<Mirror *>(items[i]))
        {
            resList << item;
        }
    }
    return resList;
}

QList<PLight *> OptixScene::getPLights()
{
    QList<PLight *> resList;
    PLight *item;
    QList<QGraphicsItem *> items = this->items();
    for (int i = 0; i < items.size(); ++i)
    {
        if (item = dynamic_cast<PLight *>(items[i]))
        {
            resList << item;
        }
    }
    return resList;
}

QList<DLight *> OptixScene::getDLights()
{
    QList<DLight *> resList;
    DLight *item;
    QList<QGraphicsItem *> items = this->items();
    for (int i = 0; i < items.size(); ++i)
    {
        if (item = dynamic_cast<DLight *>(items[i]))
        {
            resList << item;
        }
    }
    return resList;
}

/////////////////////////////////////////////////////////////////////////////

void OptixScene::actionNew()
{
    foreach (QGraphicsItem *item, this->items())
    {
        item->setSelected(true);
    }
    foreach(QGraphicsItem *item, this->selectedItems())
    {
        this->removeItem(item);
    }
    curSaveMode = unnamed;
}

void OptixScene::actionOpen()
{
    QFileDialog::Options options;
    QString selectedFilter;
    QString fileName = QFileDialog::getOpenFileName(this->views().first(),
                                tr("Open file"),
                                tr(""),
                                tr("Optix Files (*.opx)"),
                                &selectedFilter,
                                options);
    if (!fileName.isEmpty())
    {
        if (openFile(fileName))
            curSaveMode = named;
    }
}

void OptixScene::actionSave()
{
    if (curSaveMode == unnamed)
    {
        QFileDialog::Options options;
        QString selectedFilter;
        QString fileName = QFileDialog::getSaveFileName(this->views().first(),
                                    tr("Save file"),
                                    tr(""),
                                    tr("Optix Files (*.opx)"),
                                    &selectedFilter,
                                    options);
        if (!fileName.isEmpty())
        {
            saveFile(fileName);
            curSaveMode = named;
        }
    }
}


void OptixScene::actionSaveAs()
{
    QFileDialog::Options options;
    QString selectedFilter;
    QString fileName = QFileDialog::getSaveFileName(this->views().first(),
                                tr("Save file"),
                                tr(""),
                                tr("Optix Files (*.opx)"),
                                &selectedFilter,
                                options);
    if (!fileName.isEmpty())
    {
        saveFile(fileName);
        curSaveMode = named;
    }
}

bool OptixScene::openFile(QString fileName)
{
    QDomDocument doc;
    QDomElement domElement;
    QFile file(fileName);

    if (file.open(QIODevice::ReadOnly))
    {
        if (doc.setContent(&file))
        {
            actionNew();
            domElement = doc.documentElement();
            traverseNode(domElement);
        }
        file.close();
        return 1;
    }
    else
        return 0;
}

void OptixScene::traverseNode(QDomNode &node)
{
    QDomNode domNode = node.firstChild();
    while (!domNode.isNull())
    {
        if (domNode.isElement())
        {
            QDomElement domElement = domNode.toElement();
            if (!domElement.isNull())
            {
                if (domElement.tagName() == "element")
                {
                    QString type = domElement.attribute("type", "");
                    loadElement(type, domElement);
                }
            }
        }
        domNode = domNode.nextSibling();
    }
}

void OptixScene::saveFile(QString fileName)
{
    QDomDocument doc("experiment");
    QDomElement domElement = doc.createElement("experiment");
    doc.appendChild(domElement);

    foreach (QGraphicsItem *item, items())
    {
        domElement.appendChild(addElement(doc, item));
    }

    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly))
    {
        QTextStream(&file) << doc.toString();
        file.close();
    }
}

QDomElement OptixScene::addElement(QDomDocument &doc, QGraphicsItem *item)
{
    //x
    QDomElement elPosX = doc.createElement("posX");
    QDomText posX = doc.createTextNode(QString("%1").arg(item->pos().x()));
    elPosX.appendChild(posX);
    //y
    QDomElement elPosY = doc.createElement("posY");
    QDomText posY = doc.createTextNode(QString("%1").arg(item->pos().y()));
    elPosY.appendChild(posY);

    Border *b;
    TransparentBorder *tb;
    DLight *dl;
    PLight *pl;
    Mirror *m;
    if (b = dynamic_cast<Border *>(item))
    {
        QDomElement newEl = doc.createElement("element");
        QDomAttr newAttr = doc.createAttribute("type");
        newAttr.setValue("border");
        newEl.setAttributeNode(newAttr);

        //h
        QDomElement hEl = doc.createElement("h");
        QDomText tH = doc.createTextNode(QString("%1").arg(b->getH()));
        hEl.appendChild(tH);

        newEl.appendChild(elPosX);
        newEl.appendChild(elPosY);
        newEl.appendChild(hEl);
        newEl.appendChild(makeInfoItem(doc, item));
        newEl.appendChild(makePolygonInfo(doc, b->polygon()));
        return newEl;
    }
    else if (tb = dynamic_cast<TransparentBorder *>(item))
    {
        QDomElement newEl = doc.createElement("element");
        QDomAttr newAttr = doc.createAttribute("type");
        newAttr.setValue("transparent border");
        newEl.setAttributeNode(newAttr);

        //n
        QDomElement nEl = doc.createElement("n");
        QDomText tN = doc.createTextNode(QString("%1").arg(tb->getN()));
        nEl.appendChild(tN);

        newEl.appendChild(elPosX);
        newEl.appendChild(elPosY);
        newEl.appendChild(nEl);
        newEl.appendChild(makeInfoItem(doc, item));
        newEl.appendChild(makePolygonInfo(doc, tb->polygon()));
        return newEl;
    }
    else if (dl = dynamic_cast<DLight *>(item))
    {
        QDomElement newEl = doc.createElement("element");
        QDomAttr newAttr = doc.createAttribute("type");
        newAttr.setValue("direct light");
        newEl.setAttributeNode(newAttr);

        //d
        QDomElement dEl = doc.createElement("d");
        QDomText tD = doc.createTextNode(QString("%1").arg(dl->getD()));
        dEl.appendChild(tD);
        //length
        QDomElement lEl = doc.createElement("length");
        QDomText tL = doc.createTextNode(QString("%1").arg(dl->getLength()));
        lEl.appendChild(tL);
        //numLines
        QDomElement nlEl = doc.createElement("numLines");
        QDomText tNL = doc.createTextNode(QString("%1").arg(dl->getNumLines()));
        nlEl.appendChild(tNL);
        //lineSize
        QDomElement lsEl = doc.createElement("lineSize");
        QDomText tLS = doc.createTextNode(QString("%1").arg(dl->getLineSize()));
        lsEl.appendChild(tLS);

        newEl.appendChild(elPosX);
        newEl.appendChild(elPosY);
        newEl.appendChild(dEl);
        newEl.appendChild(lEl);
        newEl.appendChild(nlEl);
        newEl.appendChild(lsEl);
        newEl.appendChild(makeInfoItem(doc, item));
        return newEl;
    }
    else if (pl = dynamic_cast<PLight *>(item))
    {
        QDomElement newEl = doc.createElement("element");
        QDomAttr newAttr = doc.createAttribute("type");
        newAttr.setValue("point light");
        newEl.setAttributeNode(newAttr);

        //h
        QDomElement hEl = doc.createElement("h");
        QDomText tH = doc.createTextNode(QString("%1").arg(pl->getH()));
        hEl.appendChild(tH);
        //size
        QDomElement sEl = doc.createElement("size");
        QDomText tS = doc.createTextNode(QString("%1").arg(pl->getSize()));
        sEl.appendChild(tS);

        newEl.appendChild(elPosX);
        newEl.appendChild(elPosY);
        newEl.appendChild(hEl);
        newEl.appendChild(sEl);
        newEl.appendChild(makeInfoItem(doc, item));
        return newEl;
    }
    else if (m = dynamic_cast<Mirror *>(item))
    {
        QDomElement newEl = doc.createElement("element");
        QDomAttr newAttr = doc.createAttribute("type");
        newAttr.setValue("mirror");
        newEl.setAttributeNode(newAttr);

        newEl.appendChild(elPosX);
        newEl.appendChild(elPosY);
        newEl.appendChild(makeInfoItem(doc, item));
        newEl.appendChild(makePolygonInfo(doc, m->polygon()));
        return newEl;
    }
    return QDomElement();
}

QDomElement OptixScene::makePolygonInfo(QDomDocument &doc, const QPolygonF &poly)
{
    QDomElement newEl = doc.createElement("polygon");

    for (int i = 0; i < poly.size(); ++i)
    {
        QDomElement pEl = doc.createElement("point");
        QDomAttr aAttr = doc.createAttribute("number");
        aAttr.setValue(QString("%1").arg(i+1));
        pEl.setAttributeNode(aAttr);

        QPointF p = poly[i];
        QDomElement elX = doc.createElement("x");
        QDomText tX = doc.createTextNode(QString("%1").arg(p.x()));
        elX.appendChild(tX);

        QDomElement elY = doc.createElement("y");
        QDomText tY = doc.createTextNode(QString("%1").arg(p.y()));
        elY.appendChild(tY);

        pEl.appendChild(elX);
        pEl.appendChild(elY);
        newEl.appendChild(pEl);
    }

    return newEl;
}

QDomElement OptixScene::makeInfoItem(QDomDocument &doc, QGraphicsItem *item)
{
    OptixItem *oi;
    oi = dynamic_cast<OptixItem *>(item);

    QDomElement newEl = doc.createElement("info");

    QDomElement elAngle = doc.createElement("angle");
    QDomText tAngle = doc.createTextNode(QString("%1").arg(oi->getAngle()));
    elAngle.appendChild(tAngle);

    QDomElement elSx = doc.createElement("sx");
    QDomText tSx = doc.createTextNode(QString("%1").arg(oi->getScX()));
    elSx.appendChild(tSx);

    QDomElement elSy = doc.createElement("sy");
    QDomText tSy = doc.createTextNode(QString("%1").arg(oi->getScY()));
    elSy.appendChild(tSy);

    QDomElement elColor = doc.createElement("color");
    QDomText tColor = doc.createTextNode(oi->getColor().name());
    elColor.appendChild(tColor);

    newEl.appendChild(elAngle);
    newEl.appendChild(elSx);
    newEl.appendChild(elSy);
    newEl.appendChild(elColor);

    return newEl;
}
/////////////////////////////////////////////////////////
void OptixScene::loadElement(QString type, QDomNode &node)
{
    QDomNode domNode = node.firstChild();
    if (type == "border")
    {
        qreal posX;
        qreal posY;
        qreal h;
        QColor color;
        qreal angle;
        qreal sx;
        qreal sy;
        QPolygonF poly;
        while (!domNode.isNull())
        {
            if (domNode.isElement())
            {
                QDomElement domElement = domNode.toElement();
                if (!domElement.isNull()) {
                    if (domElement.tagName() == "posX") {
                        posX = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "posY") {
                        posY = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "h") {
                        h = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "info") {
                        loadInfo(domNode, angle, sx, sy, color);
                    }
                    if (domElement.tagName() == "polygon") {
                        loadPolygon(domNode, poly);
                    }
                }
            }
            domNode = domNode.nextSibling();
        }
        Border *b = new Border(h, &poly, color);
        b->setPos(posX, posY);
        rotateItem(b, angle);
        scaleItem(b, sx*50, sy*50);
        this->addItem(b);
    }
    else if (type == "transparent border")
    {
        qreal posX;
        qreal posY;
        qreal n;
        QColor color;
        qreal angle;
        qreal sx;
        qreal sy;
        QPolygonF poly;
        while (!domNode.isNull())
        {
            if (domNode.isElement())
            {
                QDomElement domElement = domNode.toElement();
                if (!domElement.isNull()) {
                    if (domElement.tagName() == "posX") {
                        posX = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "posY") {
                        posY = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "n") {
                        n = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "info") {
                        loadInfo(domNode, angle, sx, sy, color);
                    }
                    if (domElement.tagName() == "polygon") {
                        loadPolygon(domNode, poly);
                    }
                }
            }
            domNode = domNode.nextSibling();
        }
        TransparentBorder *b = new TransparentBorder(&poly, n,
                                   QColor(color.red(), color.green(), color.blue(), 100));
        b->setPos(posX, posY);
        rotateItem(b, angle);
        scaleItem(b, sx*50, sy*50);
        this->addItem(b);
    }
    else if (type == "direct light")
    {
        qreal posX;
        qreal posY;
        QColor color;
        qreal angle;
        qreal sx;
        qreal sy;
        qreal d;
        qreal length;
        int numLines;
        int lineSize;
        while (!domNode.isNull())
        {
            if (domNode.isElement())
            {
                QDomElement domElement = domNode.toElement();
                if (!domElement.isNull()) {
                    if (domElement.tagName() == "posX") {
                        posX = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "posY") {
                        posY = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "d") {
                        d = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "length") {
                        length = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "numLines") {
                        numLines = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "lineSize") {
                        lineSize = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "info") {
                        loadInfo(domNode, angle, sx, sy, color);
                    }
                }
            }
            domNode = domNode.nextSibling();
        }
        DLight *b = new DLight(&shadMap, d, length, numLines, lineSize, color);
        b->setPos(posX, posY);
        rotateItem(b, angle);
        scaleItem(b, sx*50, sy*50);
        this->addItem(b);
    }
    if (type == "point light")
    {
        qreal posX;
        qreal posY;
        QColor color;
        qreal angle;
        qreal sx;
        qreal sy;
        qreal h;
        qreal size;
        while (!domNode.isNull())
        {
            if (domNode.isElement())
            {
                QDomElement domElement = domNode.toElement();
                if (!domElement.isNull()) {
                    if (domElement.tagName() == "posX") {
                        posX = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "posY") {
                        posY = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "h") {
                        h = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "size") {
                        size = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "info") {
                        loadInfo(domNode, angle, sx, sy, color);
                    }
                }
            }
            domNode = domNode.nextSibling();
        }
        PLight *b = new PLight(&shadMap, h, size, color);
        b->setPos(posX, posY);
        rotateItem(b, angle);
        scaleItem(b, sx*50, sy*50);
        this->addItem(b);
    }
    else if (type == "mirror")
    {
        qreal posX;
        qreal posY;
        QColor color;
        qreal angle;
        qreal sx;
        qreal sy;
        QPolygonF poly;
        while (!domNode.isNull())
        {
            if (domNode.isElement())
            {
                QDomElement domElement = domNode.toElement();
                if (!domElement.isNull()) {
                    if (domElement.tagName() == "posX") {
                        posX = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "posY") {
                        posY = domElement.text().toDouble(NULL);
                    }
                    if (domElement.tagName() == "info") {
                        loadInfo(domNode, angle, sx, sy, color);
                    }
                    if (domElement.tagName() == "polygon") {
                        loadPolygon(domNode, poly);
                    }
                }
            }
            domNode = domNode.nextSibling();
        }
        Mirror *b = new Mirror(&poly, QColor(color.red(), color.green(), color.blue(), 100));
        b->setPos(posX, posY);
        rotateItem(b, angle);
        scaleItem(b, sx*50, sy*50);
        this->addItem(b);
    }
}

void OptixScene::loadInfo(QDomNode domNode, qreal &angle, qreal &sx, qreal &sy, QColor &color)
{
    QDomNode domNode2 = domNode.firstChild();
    while (!domNode2.isNull())
    {
        if (domNode2.isElement())
        {
            QDomElement domElement2 = domNode2.toElement();
            if (!domElement2.isNull()) {
                if (domElement2.tagName() == "angle") {
                    angle = domElement2.text().toDouble(NULL);
                }
                if (domElement2.tagName() == "sx") {
                    sx = domElement2.text().toDouble(NULL);
                }
                if (domElement2.tagName() == "sy") {
                    sy = domElement2.text().toDouble(NULL);
                }
                if (domElement2.tagName() == "color") {
                    color = QColor(domElement2.text());
                }
            }
        }
        domNode2 = domNode2.nextSibling();
    }
}

void OptixScene::loadPolygon(QDomNode domNode, QPolygonF &poly)
{
    QDomNode domNode2 = domNode.firstChild();
    while (!domNode2.isNull())
    {
        QPointF p;
        //x
        QDomNode domNodeX = domNode2.firstChild();
        if (domNodeX.isElement()) {
            QDomElement elx = domNodeX.toElement();
            p.setX(elx.text().toDouble());
        }
        //y
        QDomNode domNodeY = domNodeX.nextSibling();
        if (domNodeY.isElement()) {
            QDomElement ely = domNodeY.toElement();
            p.setY(ely.text().toDouble());
        }
        poly << p;
        qDebug() << p.x() << " " << p.y() << endl;
        domNode2 = domNode2.nextSibling();
    }
}
